package jp.co.systemi.asp.workflow.user;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;

import jp.co.systemi.asp.utils.BeanUtils;
import jp.co.systemi.asp.utils.DModalWindow;
import jp.co.systemi.asp.workflow.ICallback;
import jp.co.systemi.asp.workflow.Main;
import jp.co.systemi.asp.workflow.annotation.FormInput;
import jp.co.systemi.asp.workflow.annotation.Required;
import jp.co.systemi.asp.workflow.data.Group;
import jp.co.systemi.asp.workflow.data.GroupMeta;
import jp.co.systemi.asp.workflow.data.User;
import jp.co.systemi.asp.workflow.data.UserGroup;
import jp.co.systemi.asp.workflow.data.UserGroupMeta;
import jp.co.systemi.asp.workflow.data.UserMeta;
import jp.co.systemi.asp.workflow.group.GroupSelect;

import org.apache.wicket.Page;
import org.apache.wicket.PageParameters;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.authorization.strategies.role.Roles;
import org.apache.wicket.authorization.strategies.role.annotations.AuthorizeInstantiation;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.Radio;
import org.apache.wicket.markup.html.form.RadioGroup;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.PropertyModel;
import org.datanucleus.util.StringUtils;
import org.slim3.datastore.Datastore;
import org.slim3.datastore.GlobalTransaction;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Transaction;
@AuthorizeInstantiation(Roles.ADMIN)
/**
 * 管理者から他のユーザーを編集する
 */
public class UserReg extends Main implements ICallback {
    private static final Logger log = Logger.getLogger(UserReg.class.getName());
    public static final String UNIQUE_KEY = "uniqueLoginId";
    private User model = new User();
    // 編集用オブジェクト
    private UserGroup edit = new UserGroup();

    @FormInput
    @Required
    public TextField<String> loginId = new TextField<String>("wi_loginId",
            new PropertyModel<String>(this, "model.loginId"));
    @FormInput
    @Required
    public TextField<String> lastName = new TextField<String>("wi_lastName",
            new PropertyModel<String>(this, "model.lastName"));
    @FormInput
    @Required
    public TextField<String> firstName = new TextField<String>("wi_firstName",
            new PropertyModel<String>(this, "model.firstName"));
    @FormInput
    public TextField<String> seq = new TextField<String>("wi_seq",
            new PropertyModel<String>(this, "model.seq"));

    // Javaコンパイルのため、ここに定義しておく、なお、フォームの直下ではないため、@FormInputを付けない
    TextField<String> editGroupName = new TextField<String>("wi_groupName",
            new PropertyModel<String>(this, "edit.groupName"));
    /**
     * 新規、編集モードに応じて、ボタンの名前を変更する
     */
    @SuppressWarnings("unused")
    private String buttonName = "";
    // モードの応じて、ボタン名を変更する
    @FormInput
    public AjaxButton submit = new AjaxButton("wi_submit", new PropertyModel<String>(
            this, "buttonName")) {
        private static final long serialVersionUID = 7681411408864197000L;

        @Override
        public void onSubmit(AjaxRequestTarget target, Form<?> form) {
            Transaction tx = Datastore.beginTransaction();
            if (mode == MODE.NEW) {
                // ユニックコード制御
                if (!Datastore.putUniqueValue(UNIQUE_KEY, model.getLoginId())) {
                    error(getString("user.exists"));
                    target.addComponent(feedback);
                    return;
                }
            }
            Datastore.put(tx, model);
            tx.commit();
            // 新規の場合は編集画面へ遷移
            PageParameters pars = new PageParameters();
            pars.add("loginId", model.getLoginId());
            if (mode == MODE.NEW) {
                setResponsePage(UserReg.class, pars);
            } else {
                // ユーザ照会画面へ遷移
                setResponsePage(UserRef.class, pars);
            }
        }

    };

    // メイングループ選択用
    class MainGroup extends RadioGroup<String> {
        public MainGroup(String id, IModel<String> model) {
            super(id, model);
        }

        private static final long serialVersionUID = 6501248702196374984L;

        @Override
        protected void onSelectionChanged(Object newSelection) {
            super.onSelectionChanged(newSelection);
            GlobalTransaction gtx = Datastore.beginGlobalTransaction();
            List<Key> keys = new ArrayList<Key>();
            mainGroupCode = (String) newSelection;
            UserGroupMeta ugm = UserGroupMeta.get();
            List<UserGroup> userGroups = Datastore.query(ugm).filter(
                    ugm.loginId.equal(model.getLoginId())).sort(ugm.seq.asc)
                    .asList();
            for (UserGroup userGroup : userGroups) {
                log.info("userGroup: " + userGroup.getGroupCode());
                if (userGroup.getGroupCode().equals(mainGroupCode)) {
                    if (!userGroup.getMain()) { // 必要な分だけ更新する
                        userGroup.setMain(true);
//                        Datastore.put(userGroup);
                        keys.add(userGroup.getId());
                    }
                } else {
                    if (userGroup.getMain()) { // 必要な分だけ更新する
                        userGroup.setMain(false);
//                        Datastore.put(userGroup);
                        keys.add(userGroup.getId());
                    }
                }
            }
            gtx.put(keys);
            gtx.commit();
            UserReg.this.userGroups.clear();
            UserReg.this.userGroups.addAll(userGroups);
        }

        @Override
        protected boolean wantOnSelectionChangedNotifications() {
            return true;
        }
    }

    @FormInput
    public RadioGroup<String> radioGroup = new MainGroup("wi_radioGroup",
            new PropertyModel<String>(this, "mainGroupCode"));
    // ラジオボタンの選択値
    private String mainGroupCode = "";

    private List<UserGroup> userGroups = new ArrayList<UserGroup>();

    private Form<User> form = new MainForm<User>(this, "wi_userRegForm"); // 複数サブミットボタンがありまして、動きが異なる場合は、各ボタンのonSubmitにて実装

    public UserReg(PageParameters pars) {
        String strLoginId = pars.getString("loginId");
        UserMeta um = UserMeta.get();
        User user = Datastore.query(um).filter(um.loginId.equal(strLoginId))
                .asSingle();
        if(user == null){
            error(getString("data.error"));
            user = new User();
        }
        BeanUtils.copy(model, user);
        loginId.setEnabled(false);
        mode = MODE.EDIT;
        buttonName = "保存";
        init();
    }

    public UserReg() {
        init();
    }

    public void init() {
        log.info("UserRegistration: begin");
        // @FormInputの記述があるから、form.add()の記述が不要
        // form.add(submit);

        // ユーザーグループリスト
        final WebMarkupContainer tblGroups = new WebMarkupContainer(
                "wi_tblGroups");
        tblGroups.setOutputMarkupId(true);
        radioGroup.add(tblGroups);
        UserGroupMeta ugm = UserGroupMeta.get();
        userGroups.addAll(Datastore.query(ugm).filter(
                ugm.loginId.equal(model.getLoginId())).sort(ugm.seq.asc)
                .asList());
        tblGroups.add(new ListView<UserGroup>("wi_trGroup", userGroups) {
            private static final long serialVersionUID = 1L;

            @Override
            protected void populateItem(ListItem<UserGroup> item) {
                final UserGroup userGroup = (UserGroup) item.getModelObject();
                GroupMeta gm = GroupMeta.get();
                Group group = Datastore.query(gm).filter(gm.code.equal(userGroup.getGroupCode())).asSingle();
                if(group != null){
                    userGroup.setGroupName(group.getName());
                }
                if (userGroup.getMain()) {
                    mainGroupCode = userGroup.getGroupCode();
                }
                item.add(new Label("wi_tdSeq", new PropertyModel<Integer>(
                        userGroup, "seq")));
                item.add(new Label("wi_tdGroupName", new PropertyModel<String>(
                        userGroup, "groupName")));
                // 役割（代表取締役、部長など、肩書き）
                item.add(new Label("wi_tdRole", new PropertyModel<String>(
                        userGroup, "role")));

                Radio<String> radio = new Radio<String>("wi_tdMain",
                        new PropertyModel<String>(userGroup, "groupCode"));
                radioGroup.add(radio);
                item.add(radio);
                item.add(new AjaxLink<Object>("wi_tdDelete") {
                    private static final long serialVersionUID = 1L;

                    @Override
                    public void onClick(AjaxRequestTarget target) {
                        log.info("delete");
                        Datastore.delete(userGroup.getId());
                        userGroups.remove(userGroup);
                        // 順番を振りなおし
                        int i = 0;
                        for (UserGroup ug : userGroups) {
                            ug.setSeq(++i);
                        }
                        target.addComponent(form);
                    }

                });
                item.add(new AjaxLink<Object>("wi_tdEdit") {
                    private static final long serialVersionUID = 1L;

                    @Override
                    public void onClick(AjaxRequestTarget target) {
                        log.info("edit");
                        Datastore.delete(userGroup.getId());
                        userGroups.remove(userGroup);
                        edit.setRole(userGroup.getRole());
                        edit.setGroupCode(userGroup.getGroupCode());
                        edit.setGroupName(userGroup.getGroupName());
                        // 順番を振りなおし
                        int i = 0;
                        for (UserGroup ug : userGroups) {
                            ug.setSeq(++i);
                        }
                        target.addComponent(form);
                    }

                });
            }
        });
        tblGroups.add(new AjaxButton("wi_addGroup") {
            private static final long serialVersionUID = -2573012794536636414L;

            @Override
            protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
                // 入力チェック
                if (StringUtils.isEmpty(edit.getRole())) {
                    error(getString("role.empty"));
                    target.addComponent(feedback);
                    return;
                }
                if (StringUtils.isEmpty(edit.getGroupCode())) {
                    error(getString("group.empty"));
                    target.addComponent(feedback);
                    return;
                }
                // 重複チェック
                for (UserGroup p : userGroups) {
                    if (edit.getGroupCode().equals(p.getGroupCode())) {
                        error(getString("role.duplicate"));

                        target.addComponent(feedback);
                        return;
                    }
                }
                // グループの存在チェック
                GroupMeta gm = GroupMeta.get();
                Group group = Datastore.query(gm).filter(
                        gm.code.equal(edit.getGroupCode())).asSingle();
                if (group == null) {
                    error(getString("group.notexists"));

                    target.addComponent(feedback);
                    return;
                }
                // 登録する
                UserGroup userGroup = new UserGroup();
                userGroup.setGroupCode(edit.getGroupCode());
                userGroup.setLoginId(model.getLoginId());
                userGroup.setRole(edit.getRole());
                userGroup.setSeq(userGroups.size() + 1);
                if (userGroup.getSeq() == 1) {
                    userGroup.setMain(true);
                    mainGroupCode = userGroup.getGroupCode();
                }
                // roleSeqを設定
                UserGroupMeta ugm = UserGroupMeta.get();
                List<UserGroup> groupRoles = Datastore.query(ugm).filter(
                        ugm.groupCode.equal(edit.getGroupCode())).sort(
                        ugm.seq.asc).asList();
                userGroup.setRoleSeq(groupRoles.size() + 1);
                if (group != null) {
                    userGroup.setGroupName(group.getName());
                }
                Datastore.put(userGroup);
                userGroups.add(userGroup);

                edit.setRole("");
                edit.setGroupCode("");
                target.addComponent(feedback);
                target.addComponent(tblGroups);
            }
        });
        tblGroups.add(new TextField<String>("wi_role",
                new PropertyModel<String>(edit, "role")));
        tblGroups.add(editGroupName);
        editGroupName.setOutputMarkupId(true);

        // 役割のオーナーを選択あるモデルウィンドウ
        final DModalWindow ownerSelectWindow = new DModalWindow(
                "wi_selectGroupModelWindow");
        ownerSelectWindow.setTitle("グループ選択");
        ownerSelectWindow.setPageCreator(new ModalWindow.PageCreator() {
            private static final long serialVersionUID = -6364600063465337078L;

            public Page createPage() {
                return new GroupSelect(UserReg.this, ownerSelectWindow);
            }
        });

        ownerSelectWindow
                .setOKActionCallback(new ModalWindow.WindowClosedCallback() {
                    private static final long serialVersionUID = -1012735996565367949L;

                    public void onClose(AjaxRequestTarget target) {
                        target.addComponent(feedback);
                        // target.addComponent(tblGroups);
                        // テーブルの再表示をやめて、選択したグループ名を再表示だけ（メイングループのラジオボタンの表示がおかしくなるため）
                        target.addComponent(editGroupName);
                    }
                });
        ownerSelectWindow
                .setCancelActionCallback(new ModalWindow.WindowClosedCallback() {
                    private static final long serialVersionUID = -1012735996565367949L;

                    public void onClose(AjaxRequestTarget target) {
                        target.addComponent(feedback);
                        // target.addComponent(tblGroups);
                        // テーブルの再表示をやめて、選択したグループ名を再表示だけ（メイングループのラジオボタンの表示がおかしくなるため）
                        target.addComponent(editGroupName);
                    }
                });
        // 閉じるボタン（X）をクリックした時に呼ばれる
        ownerSelectWindow
                .setCloseButtonCallback(new ModalWindow.CloseButtonCallback() {
                    private static final long serialVersionUID = -2205343604513004971L;

                    public boolean onCloseButtonClicked(AjaxRequestTarget target) {
                        return true;
                    }
                });
        main.add(ownerSelectWindow);

        tblGroups.add(new AjaxButton("wi_selectGroup") {
            private static final long serialVersionUID = 6474399847088717250L;

            @Override
            protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
                ownerSelectWindow.setWindowClosedCallback(null);
                ownerSelectWindow.show(target);
                log.info("after show dialog");
            }
        }.setDefaultFormProcessing(false));
        tblGroups.add(new AjaxButton("wi_tdDeleteGroup") {
            private static final long serialVersionUID = -2573012794536636414L;

            @Override
            protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
                for (Iterator<UserGroup> itr = userGroups.iterator(); itr
                        .hasNext();) {
                    UserGroup userGroup = itr.next();
                    if (userGroup.getSelect()) {
                        itr.remove();
                        Datastore.delete(userGroup.getId());

                    }
                }
                target.addComponent(feedback);
                target.addComponent(tblGroups);
            }
        });
        if (mode == MODE.NEW) {
            tblGroups.setVisible(false);
        }

    }

    /**
     * 選択ダイアログのOKボタンを押下された時にのCALLBACK PageParametersにloginId=>選択したEmail
     */
    public void setResult(PageParameters pars) {
        log.info("setResult is called.");
        edit.setGroupCode(pars.getString("code"));
        GroupMeta gm = GroupMeta.get();
        Group group = Datastore.query(gm).filter(gm.code.equal(edit.getGroupCode())).asSingle();
        if (group != null) {
            edit.setGroupName(group.getName());
        }
    }

    /**
     * グループ選択ダイアログインターフェースのメソッド 現在の選択値をダイアログの初期表示時に表示させるため
     */
    public Object getDefault(PageParameters pars) {
        return edit.getGroupCode();
    }

    public String getEmptyMessage(PageParameters pars) {
        return getString("group.empty");
    }
}
